package model;

import java.util.Observable;


import observer.NotificationObjetCompte;

import model.exception.CompteNonInitialise;
import model.exception.CompteNonValideException;
import model.exception.ForfaitNonValideException;
import model.states.EtatCompte;
import model.states.EtatCompteCrediteur;
import model.states.EtatCompteNonCrediteur;
import model.states.EtatComptePerime;
import observer.ObserveurCompte;
import utilitaire.Date;



public class Compte extends Observable
{
	private EtatCompte etatCompte;
	private float credit;
	private int dureeMois;
	private Date dateDeCreation;
	private ForfaitCompte forfaitDureeCompte;
	private ForfaitCompte forfaitDureeAnnonce;
	private ForfaitCompte forfaitPrixAnnonce;
	

	
	public Compte(float credit, Date dateDeCreation,int dureeMois,
			ForfaitCompte forfaitDureeCompte,
			ForfaitCompte forfaitDureeAnnonce, 
			ForfaitCompte forfaitPrixAnnonce,String idA) throws IllegalArgumentException{
		super();		

		addObserver(new ObserveurCompte());
		this.dureeMois = dureeMois;
		this.credit = credit;
		this.dateDeCreation =dateDeCreation;
		this.forfaitDureeCompte = forfaitDureeCompte;
		this.forfaitDureeAnnonce = forfaitDureeAnnonce;
		this.forfaitPrixAnnonce = forfaitPrixAnnonce;
		if(credit>0){
			setEtatCompte(new EtatCompteCrediteur());
		}else{
			setEtatCompte(new EtatCompteNonCrediteur());
		}

		
	}


	/**
	 * Solde de le compte du montant déterminer par la méthode GetPrixAnnonce	
	 * Appel de la méthode solder de l'EtatCompte courant 
	 * @throws CompteNonValideException 
	 * @throws ForfaitNonValideException 
	 */
	public void solder(float prixdeBase) throws ForfaitNonValideException, CompteNonValideException{
		etatCompte.solder(this,prixdeBase);
			
	}
	/**
	 * Augmente le credit en cours
	 * @param montant le Montant a ajouter
	 * @throws CompteNonValideException 
	 */
	public void approvisioner(float montant) throws CompteNonValideException{
		etatCompte.approvisioner(this,montant);		
	}
	
	/**
	 * @return la duree du compte
	 */
	public Date getDateFinCompte(){
		int nbMois;
		try{
			nbMois=dureeMois*(int)forfaitDureeCompte.getMutiplicateur(new Date());
		}
		catch(ForfaitNonValideException e){
			nbMois=dureeMois;
		}
		return dateDeCreation.nMoisPlusTard(nbMois);
	}

	/**
	 * Retourne le prix de l'annonce �tant donn� le prix de base
	 * @return le prix d'une annonce
	 */

	public float getPrixAnnonce(float prixDeBase){
		try {
			return prixDeBase*forfaitPrixAnnonce.getMutiplicateur(Date.today());
		} catch (ForfaitNonValideException e) {
			e.printStackTrace();
			return prixDeBase;
		}
	}

	public float getPrixAnnonce(float prixBase,Date dateAnnonce)throws ForfaitNonValideException
	{
		return prixBase*forfaitPrixAnnonce.getMutiplicateur(dateAnnonce);
	}
	
	/**
	 * Retourne la dur�e d'une annonce �tant donn�es la dur�e de base.
	 * @return la dur�e en semaine
	 */
	public int getDureeAnnonce(int dureeBaseEnSemaine,Date dateAnnonce)
			throws ForfaitNonValideException
	{
		return dureeBaseEnSemaine*(int)forfaitDureeAnnonce.getMutiplicateur(dateAnnonce);

	}

	/**
	 * @param etatCompte the etatCompte to set
	 */
	public void setEtatCompte(EtatCompte etatCompte) {	
		
		if(this.etatCompte==null || !getStatus().equals(etatCompte.getStatus())){
			this.etatCompte = etatCompte;
			notificationCompte("Etat du Compte : "+getStatus());
		}		
	}

	/**
	 * @return the etatCompte
	 */
	public EtatCompte getEtatCompte() {
		return etatCompte;
	}

	/**
	 * @param credit the credit to set
	 */
	public void setCredit(float credit) {
		this.credit = credit;	
		notificationCompte("Credit : "+this.credit);
	}

	/**
	 * @return the credit
	 */
	public float getCredit() {
		return credit;
	}

	/**
	 * @param dateDeCreation the dateDeCreation to set
	 */
	public void setDateDeCreation(Date dateDeCreation) throws IllegalArgumentException{
		if(dateDeCreation!=null)this.dateDeCreation = dateDeCreation;
		else throw new IllegalArgumentException("Le champs dateDeCreation ne peut �tre null");
	}

	/**
	 * @return the dateDeCreation
	 */
	public Date getDateDeCreation() {
		return dateDeCreation;
	}

	/**
	 * @param forfaitDureeCompte the forfaitDureeCompte to set
	 */
	public void setForfaitDureeCompte(ForfaitCompte forfaitDureeCompte) {
		if (forfaitDureeCompte!=null){
			this.forfaitDureeCompte = forfaitDureeCompte;
			notificationCompte("Forfait duree compte : "+this.forfaitDureeCompte.getForfait().getNom());
			}
		else throw new IllegalArgumentException("Le forfaitDureeCompte ne peut �tre null.");
		
		
	}

	/**
	 * @return the forfaitDureeCompte
	 */
	public ForfaitCompte getForfaitDureeCompte() {
		return forfaitDureeCompte;
	}

	/**
	 * @param forfaitDureeAnnonce the forfaitDureeAnnonce to set
	 */
	public void setForfaitDureeAnnonce(ForfaitCompte forfaitDureeAnnonce) {
		if (forfaitDureeAnnonce!=null){
			this.forfaitDureeAnnonce = forfaitDureeAnnonce;
			notificationCompte("Forfait duree annonce : "+this.forfaitDureeAnnonce.getForfait().getNom());
		}
		else throw new IllegalArgumentException("Le forfaitDureeAnnonce ne peut �tre null.");
			
	}

	/**
	 * @return the forfaitDureeAnnonce
	 */
	public ForfaitCompte getForfaitDureeAnnonce() {
		return forfaitDureeAnnonce;
	}

	/**
	 * @param forfaitPrixAnnonce the forfaitPrixAnnonce to set
	 */
	public void setForfaitPrixAnnonce(ForfaitCompte forfaitPrixAnnonce) throws IllegalArgumentException{
		if (forfaitPrixAnnonce!=null){
			this.forfaitPrixAnnonce = forfaitPrixAnnonce;
			notificationCompte("Forfait prix annonce : "+this.forfaitPrixAnnonce.getForfait().getNom());
		}
		else throw new IllegalArgumentException("Le forfaitPrixAnnonce ne peut �tre null.");
	}

	/**
	 * @return the forfaitPrixAnnonce
	 */
	public ForfaitCompte getForfaitPrixAnnonce() {
		return forfaitPrixAnnonce;
	}	
	/**
	 * Notification des obsersers
	 * @param typeModifle type de modification faite
	 */
	public void notificationCompte(String typeModif){
		setChanged();
		notifyObservers(new NotificationObjetCompte(this, typeModif));
		clearChanged();
	}	
	
	public int getDureeMois() {
		return dureeMois;
	}

	public void setDureeMois(int dureeMois) throws IllegalArgumentException{
		if (dureeMois>0){ 
			this.dureeMois = dureeMois;
			notificationCompte("Duree mois : " + this.dureeMois);
		}
		else throw new IllegalArgumentException("Le champ dureeMois doit �tre positif");
	}
	/**
	 * Verification de la validite du Compte en duree
	 * @return si le Compte est perime ou non
	 */
	public boolean isPerime(){
		return !dateDeCreation.nMoisPlusTard(getDureeMois()).isPlusRecent(Date.today());
	}

	/**
	 * Renvoie le status du compte, appel méthode getStatus() de EtatCompte
	 * @return le status du compte
	 */
	public String getStatus(){
		return etatCompte.getStatus();
	}
	
}
